package com.mybatisplus.mp.lock;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.stereotype.Component;

import java.util.Arrays;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

/**
 * 分布式锁 原理
 * 使用setNX 占位成功标志锁住
 */
@Component
public class RedisLock {
    @Autowired
    private StringRedisTemplate template;

    public boolean redisLock() {
        // 占锁
        // 锁的值
        String uuid = UUID.randomUUID().toString();
        // 假设此处异常，会导致锁不被释放，死锁:需要设置过期时间,原子操作
        Boolean lock = template.opsForValue().setIfAbsent("lock", uuid, 300, TimeUnit.SECONDS);
        if (lock) {
            System.out.println("获取分布式锁成功");
            try {
                System.out.println("执行业务");
            } finally {
                //设置过期时间，需要原子操作
//            template.expire("lock", 20, TimeUnit.SECONDS);
                //原子删除脚本
                String s = " if redis.call('get',KEYS[1]) == ARGV[1] then return redis.call('del',KEYS[1]) else return 0 end";
                Long lock1 = template.execute(new DefaultRedisScript<Long>(s, Long.class), Arrays.asList("lock"), uuid);
            }
            return true;
        } else {
            System.out.println("获取分布式锁失败，等待重试");
            // 加锁失败
            return redisLock();//自旋
        }
    }
}
